<!DOCTYPE html>
<html>
    <head>
        <style>
            canvas{
                width: 90vh;
                height: 90vh;
            }
        </style>
        <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    </head>
    <body>
        <canvas width="1000" height="1000"></canvas>
        <button onclick="sco()">For Once</button>
    </body>
    <script>
        /**
        @version 0.2
        */
        var canvas = $("canvas")[0].getContext("2d");
        function drawLine(x1,y1,x2,y2){
            canvas.moveTo(x1,y1);
            canvas.lineTo(x2,y2);
            canvas.stroke();
        }
        var people =[];
        function distance(a,b){//计算距离
            return Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
        }
        function sitaGiver(rx,ry){//专门用来算角度
            let sita;//角度
            if(rx ==0) {//tan90度一生之敌
                sita = ry>0?Math.PI/2:-Math.PI/2;
            }else sita = Math.atan(ry/rx);
            if(sita == 0 && rx<0) sita = Math.PI;
            //sita 修正，因为tan函数的周期性只有一个PI
            if((rx<0&&ry<0)||(rx<0&&ry>0)) sita+=Math.PI;
            return sita;
        }
        var holeMaxX=2;
        var holeMaxY=40;
        var doubleMax = Math.pow(2,53);
        function runInThehole(){
            for(let i in people){
                let peo = people[i];
                if(peo == null) continue;
                if(peo.y>holeMaxY) {
                    people[i] = null;continue;
                }
                peo.x+=peo.vx;
                if(peo.x<0) peo.x=0.1;
                if(peo.x>holeMaxX)peo.x=holeMaxX-0.1;
                peo.y+=peo.vy; 
                if(peo.vy<=1+Math.random()*0.5) peo.vy+=1;//驱动力
                //v1
                // for(let ii in people){
                //     if(i==ii) continue;
                //     peoI = people[ii];
                //     if(distance(peo,peoI) <2){//发生碰撞
                //             //peo.vx=(peoI.vx<0?1:-1)*Math.max(Math.abs(peo.vx),0.5);
                //             peo.vx=0;
                //             if(peo.y<peoI.y)peo.vy=0;
                //     }
                // }
                let accuracy = 128;
                let acuR = Math.PI/accuracy/2;
                let minsit=0;let minWt=doubleMax;
                for(let sitk =acuR;sitk<=Math.PI;sitk+=acuR){
                    let res = 0;
                    
                    for(let ii in people){
                        let peoI = people[ii];
                        if(people[ii] == null) continue;
                        if(i == ii || peoI.y-1<= peo.y || ((distance(peo,peoI)>2))) continue;
                        //console.log(Math.abs(peo.x-peoI.x)<0.1);

                        res+=1/(Math.abs(sitaGiver(peoI.x-peo.x,peoI.y-peo.y)-sitk)*distance(peoI,peo));
                    }
                    //  res+=1/(Math.abs((Math.PI-sitk)*peo.x))*0.1;
                    //  res+=1/(Math.abs((sitk)*(holeMaxX-peo.x)))*0.1;
                    console.log(i+" "+sitk+" "+res)
                    if(res>=0 && res<minWt){
                        minsit = sitk;
                        minWt = res;
                    }
                    if(res ==0){//轨道修正
                        minsit = Math.PI/2;
                        minWt = Math.random()*0.5;
                        break;
                    }
                }
                //Math.sqrt(peoI.vx*peoI.vx+peoI.vy*peoI.vy);
                let vabs = Math.min(Math.max(0.1/minWt,0.1),1);
                //console.log(minWt);
                let oldSita =sitaGiver(peo.vx,peo.vy);
                minsit = oldSita+(minsit-oldSita)*0.5;
                peo.vx = vabs*Math.cos(minsit);
                peo.vy = vabs*Math.sin(minsit);
                // if(peo.x<=1){
                //     peo.vx=0.5;
                // }
                // if(peo.x>=7){
                //     peo.vx=0.5;
                // }

            }
        }
        function displayTheHole(){
            canvas.fillStyle = "white";
            canvas.fillRect(0,0,1000,1000);
            let lefx = 200;
            let rgtx = 400;
            let upy = 20;
            let downy = 500;
            let wid = rgtx-lefx;let hei = downy-upy;
            // canvas.fillStyle = "red";
            // for(let i in people){
            //     if(people[i] == null) continue;
            //     canvas.beginPath();
            //     canvas.arc(lefx+wid*people[i].x/holeMaxX,upy+wid*people[i].y/holeMaxX,wid*1/holeMaxX+0.3,0,2*Math.PI);
            //     canvas.fill();
            // }
            canvas.fillStyle = "black";
            for(let i in people){
                if(people[i] == null) continue;
                canvas.beginPath();
                canvas.arc(lefx+wid*people[i].x/holeMaxX,upy+wid*people[i].y/holeMaxX,wid*1/holeMaxX,0,2*Math.PI);
                canvas.fill();
            }
            canvas.beginPath();
            drawLine(lefx,upy,lefx,downy);
            drawLine(rgtx,upy,rgtx,downy);
        }
        function newPeo(x,y,vx,vy){
            people.push({
                x:x,
                y:y,
                vx:vx,
                vy:vy
            });
        }
        
        function summon(){//forTest
            let a;//测试xy
            let undone = true;
            while(undone){
                a={x:0+Math.random()*2,y:0+Math.random()*20}
                undone = false;
                for(let i in people){
                    if(people[i] == null) continue;
                    if(distance(a,people[i]) <2 || a.x<=1 || a.x>=holeMaxX-1) {
                        undone = false;break;
                    }
                }
            }
            newPeo(a.x,a.y,-0.5+Math.random(),-0.5+Math.random());
        }
        function sco(){
            runInThehole();
            displayTheHole();
        }
        for(let i =0;i<60;i++){
            summon();
        }
        displayTheHole();
        setInterval("sco()",100);
        //setInterval("summon()",100)

    </script>
</html>